package com.cicadasmall.support.aspect;

import com.cicadasmall.common.constant.Constant;
import com.cicadasmall.common.exception.ServiceException;
import com.cicadasmall.common.func.Fn;
import com.cicadasmall.common.utils.ControllerUtil;
import com.cicadasmall.redis.utils.RedisUtils;
import com.cicadasmall.support.annotation.AvoidRepeatSubmit;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * AvoidRepeatSubmitAspect 基于redis的放重提交注解
 *
 * @author Jin
 */
@Slf4j
@Component
@Aspect
public class AvoidRepeatSubmitAspect {

    @Around("@annotation(avoidRepeatSubmit)")
    public Object around(ProceedingJoinPoint point, AvoidRepeatSubmit avoidRepeatSubmit) throws Throwable {
        HttpServletRequest request = ControllerUtil.getHttpServletRequest();
        if (avoidRepeatSubmit != null) {
            String redisKey = getAvoidRepeatSubmitRedisKey(getAccessToken(request), request.getServletPath());
            String redisValue = RedisUtils.me().get(redisKey);
            if (Fn.isEmpty(redisValue)) {
                RedisUtils.me().setEx(redisKey, request.getMethod(), avoidRepeatSubmit.lockTime() * 5, TimeUnit.MILLISECONDS);
                return true;
            } else {
                if (Fn.notEqual(request.getMethod(), redisValue)) return true;
                throw new ServiceException("请勿重复提交！");
            }
        } else {
            return point.proceed();
        }
    }

    private String getAvoidRepeatSubmitRedisKey(String token, String path) {
        return Constant.PREFIX + "avoid_repeat_submit_lock:" + token + ":" + path;
    }

    private static String getAccessToken(HttpServletRequest request) {
        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (header == null || !header.startsWith("Bearer ")) {
            throw new UnapprovedClientAuthenticationException("请求头中没有找到Token信息！");
        }
        return header.substring(7);
    }

}
